
#ifndef EVENTHANDLER_H
#define EVENTHANDLER_H

#include <string.h>

#define CREATE_EVENT_0(CLASSNAME, IDSTRING, QUEUE) \
const char * const IDSTRING = # IDSTRING ;         \
class CLASSNAME : public events::Event{            \
public:                                            \
  CLASSNAME () : events::Event(IDSTRING, QUEUE){}; \
  Event * copy() const {return new CLASSNAME();};  \
};

#define CREATE_EVENT_1(CLASSNAME, IDSTRING, QUEUE, PARAM1TYPE, PARAM1) \
const char * const IDSTRING = # IDSTRING ;                             \
class CLASSNAME : public events::Event{                                \
public:                                                                \
  PARAM1TYPE PARAM1;                                                   \
  CLASSNAME (PARAM1TYPE a) : events::Event(IDSTRING, QUEUE){PARAM1=a;};\
  Event * copy() const {return new CLASSNAME(PARAM1);};                \
};

#define CREATE_EVENT_2(CLASSNAME, IDSTRING, QUEUE, PARAM1TYPE, PARAM1, PARAM2TYPE, PARAM2) \
const char * const IDSTRING = # IDSTRING ;                                                 \
class CLASSNAME : public events::Event{                                                    \
public:                                                                                    \
  PARAM1TYPE PARAM1;                                                                       \
  PARAM2TYPE PARAM2;                                                                       \
  CLASSNAME(PARAM1TYPE a, PARAM2TYPE b):events::Event(IDSTRING, QUEUE){PARAM1=a;PARAM2=b;};\
  Event * copy() const {return new CLASSNAME(PARAM1,PARAM2);};                             \
};

#define CREATE_EVENT_3(CLASSNAME, IDSTRING, QUEUE, TYPE1, PARAM1, TYPE2, PARAM2, TYPE3, PARAM3) \
const char * const IDSTRING = # IDSTRING ;                                                      \
class CLASSNAME : public events::Event{                                                         \
public:                                                                                         \
  TYPE1 PARAM1;                                                                                 \
  TYPE2 PARAM2;                                                                                 \
  TYPE3 PARAM3;                                                                                 \
  CLASSNAME(TYPE1 a,TYPE2 b,TYPE3 c):events::Event(IDSTRING,QUEUE){PARAM1=a;PARAM2=b;PARAM3=c;};\
  Event * copy() const {return new CLASSNAME(PARAM1,PARAM2,PARAM3);};                           \
};

#define CREATE_EVENT_4(CLASSNAME, IDSTRING, QUEUE, TYPE1, PARAM1, TYPE2, PARAM2, TYPE3, PARAM3, TYPE4, PARAM4)   \
const char * const IDSTRING = # IDSTRING ;                                                                       \
class CLASSNAME : public events::Event{                                                                          \
public:                                                                                                          \
  TYPE1 PARAM1;                                                                                                  \
  TYPE2 PARAM2;                                                                                                  \
  TYPE3 PARAM3;                                                                                                  \
  TYPE4 PARAM4;                                                                                                  \
  CLASSNAME(TYPE1 a,TYPE2 b,TYPE3 c,TYPE4 d):events::Event(IDSTRING,QUEUE){PARAM1=a;PARAM2=b;PARAM3=c;PARAM4=d;};\
  Event * copy() const {return new CLASSNAME(PARAM1,PARAM2,PARAM3,PARAM4);};                                     \
};

#define CREATE_EVENT_5(CLASSNAME, IDSTRING, QUEUE, TYPE1, PARAM1, TYPE2, PARAM2, TYPE3, PARAM3, TYPE4, PARAM4, TYPE5, PARAM5)     \
const char * const IDSTRING = # IDSTRING ;                                                                                        \
class CLASSNAME : public events::Event{                                                                                           \
public:                                                                                                                           \
  TYPE1 PARAM1;                                                                                                                   \
  TYPE2 PARAM2;                                                                                                                   \
  TYPE3 PARAM3;                                                                                                                   \
  TYPE4 PARAM4;                                                                                                                   \
  TYPE5 PARAM5;                                                                                                                   \
  CLASSNAME(TYPE1 a,TYPE2 b,TYPE3 c,TYPE4 d,TYPE5 e):events::Event(IDSTRING,QUEUE){PARAM1=a;PARAM2=b;PARAM3=c;PARAM4=d;PARAM5=e;};\
  Event * copy() const {return new CLASSNAME(PARAM1,PARAM2,PARAM3,PARAM4,PARAM5);};                                               \
};

namespace events
{
    // Queue flags used to specify what queue to post an event to
    const unsigned long APP_QUEUE   = 0x01;
    const unsigned long MAIN_QUEUE  = 0x02;
    const unsigned long EVERY_QUEUE = APP_QUEUE | MAIN_QUEUE;

    const char * const UNKNOWN_EVENT = "UNKNOW_EVENT";

    inline bool CompareEvents(const char * t1, const char * t2) {return !strcmp(t1, t2);};

    class Event
    {
        friend void Fire(Event * event);
        friend void remEvent(Event * event);

    public:
        Event();
        ~Event();

        Event(const Event & rhs);
        Event(const char * type, unsigned long queue);

        const char * type() const;

        virtual Event * copy() const;

    protected:
      // this isn't necessary, we can cut it
      virtual void _copyData(Event * copy) const;

    private:
        unsigned long _queue;
        const char * _type;
        unsigned long _copies;
    };

// Functions ///////////////////////////////////////////////////
    
    // Fire ////////////////////////////////////////////////////
    //   Posts the event passed. Event should be created with 
    //   new: 
    //     Fire(new SomeEvent(args));
    //   The event system will clean up all events, they should
    //   not be deleted manually.
    void Fire(Event * event);

    // PeekEvent ///////////////////////////////////////////////
    //   Returns a pointer to the event at the front of the 
    //   specified queue. Returns null for an invalid or empty
    //   queue.
    const Event * PeekEvent(unsigned long queue);

    // PopEvent ////////////////////////////////////////////////
    //   Removes the front element of all specified queues.
    void PopEvent(unsigned long queue);

}; // end namespace events

#endif
